/**
\file IO.h
*/
#pragma once
#include <lostlbase.h>
#include <fstream>
#include "../System.h"

namespace System { namespace IO {

	class FileSystemInfo
	{
	public:
	protected:
		string	m_directory;
		DateTime	get_CreationTime() const;
		void set_CreationTime(const DateTime & creationTime);
	private:
		string	m_fullPath;
	};

	class DirectoryInfo : public FileSystemInfo
	{
	public:
		DirectoryInfo(const char *directory);

	};

	union SearchOption
	{
		SearchOption( int value) : m_value(value) {}
		enum { TopDirectoryOnly = 0, AllDirectories = 1 };
	private:
		int m_value;
	};

#undef createDirectory
	class Directory
	{
	public:
		static DirectoryInfo createDirectory(const char *directory);
		static string GetCurrentDirectory();
		static void Delete(const char *directory);
		static void Delete(const char *directory,bool recursive);
		static bool Exists(const char *directory);
		static std::vector<std::string> GetFiles(const char *path, const char *searchPattern, SearchOption searchOption );
	};

	union FileMode
	{
		FileMode( int value) : m_value(value) {}
		enum { CreateNew = 1, Create = 2, Open = 3, OpenOrCreate = 4, Truncate = 5,	Append = 6 };
		inline bool HasFlag(FileMode fileMode)	{ return (fileMode.m_value & m_value) == fileMode.m_value; }
	private:
		int m_value;
	};

	union FileAccess
	{
		FileAccess( int value) : m_value(value) {}
		enum { Read = 1, Write = 2, ReadWrite = 3 };
		inline bool HasFlag(FileAccess fileAccess)	{ return (fileAccess.m_value & m_value) > 0; }
	private:
		int m_value;
	};

	union FileShare
	{
		FileShare( int value ) : m_value(value)	{}
		enum { None = 0, Read = 1, Write = 2, ReadWrite = 3, Delete = 4, Inheritable = 16 };
		inline bool HasFlag(FileShare fileShare)	{ return (fileShare.m_value & m_value) > 0; }
	private:
		int m_value;
	};


	class IOException //: public System::SystemException
	{
	public:
		IOException(const char *operation);// : SystemException(operation) {}
		IOException(char *operation);// : SystemException(operation) {}
	};

	class FileNotFoundException : public IOException
	{
	public:
		FileNotFoundException(char *fileName) : IOException(fileName) {}
	};

	// We undef these WIN32 macros. We should always call the API explicitly with a W following the function name. i.e. GetTempPathW
#undef GetTempPath
#undef GetTempFileName
	class Path
	{
	public:
		static const char AltDirectorySeparatorChar = '/';
		static const char DirectorySeparatorChar = '\\';
		static const char PathSeparator = ';';
		static const char VolumeSeparatorChar = ':';
		static void			AddEndDirectorySeparator(string& path);
		static void			Append( string& path, const char *addedPath );
		static void			AppendUniqueFileName( string &path, const char *extension );
		static std::string	BuildStandardPath( System::Environment::SpecialFolder pathId, const char *additionalPath );
		static std::string	ChangeExtension( const char *path, const char *extension );
		static std::string	Combine( const char *path0, const char *path1);
		static std::string	Combine( const char *path0, const char *path1, const char *path2);
		static std::string	Combine( const char *path0, const char *path1, const char *path2, const char *path3);
		static std::string	GetDirectoryName( const char *fullPath );
		static std::string	GetExtension(const char *fileName);
		static std::string	GetFileName(const char *fullPath);
		static std::string	GetFileNameWithoutExtension( const char * path );
		static const char	*GetInvalidPathChars();
		static std::string	GetPathRoot( const char *path );
		static std::string	GetRandomFileName();
		static std::string	GetTempFileName();
		static std::string	GetTempPath();
		static bool			HasExtension( const char *path );
		static bool			IsPathRooted( const char *path );
		static string		MakeTemporary();
	private:
		static std::string AppendDirectorySeparator(const char *path);
		static bool EndsWithDirectorySeparator(const char *path);
	};

	union SeekOrigin
	{
	public:
		SeekOrigin(int value) : m_value(value) {}
		enum { Begin=0,Current=1,End=2 };
		operator int() { return m_value; };
	private:
		int m_value;
	};

	class Stream : public lo::object
	{
	public:
		void	Close();
		void	CopyTo( Stream &destination );
		int		get_Length();
		int		Read(std::vector<unsigned char> &data, int offset, int length);
		virtual int ReadByte();
		long	Seek( long offset, SeekOrigin origin );
		void	SetLength( long value );
		int		Write(const std::vector<unsigned char> &data, int offset, int length);
	private:
		lo::object m_pimpl;
		inline lo::Pimpl *pimpl()	{ return (lo::Pimpl *)m_pimpl.Ptr();}
	};

	class FileStream : public fstream
	{
	public:
		FileStream( const char *path, FileMode mode );
		~FileStream()	{ if(m_fp) fclose(m_fp); }
		int		Printf(const char *format,...);
	private:
		FileStream(FILE * fp) : m_fp(fp) {}
		FILE	*m_fp;
	};

	class File
	{
	public:
		/** True if the file exists and false if not. */
		static bool Exists( const char *fileName );
		static const char *ExistsThrow(const char *fileName);
		static FileStream Open( const char *fileName, FileMode fileMode);
		static FileStream Open( const char *fileName, FileMode fileMode, FileAccess fileAccess = FileAccess::ReadWrite, FileShare fileShare = FileShare::None );
		/** Returns all the bytes from the given file and if it fails for any reason, throws an exception. i.e. file_not_found or access_denied. */
		static vector<unsigned char> ReadAllBytes(const char *fileName);
		/** Writes all the data to the given fileName */
		static void WriteAllBytes( const char *fileName, unsigned char *data, int length );
	private:
	};

	class MemoryStream : public Stream
	{
	public:
		MemoryStream(const std::vector<unsigned char>& buffer);
	};

	class TextReader : public lo::object
	{
	public:
		std::string ReadToEnd();
	};

	class StreamReader : public TextReader
	{
	public:
		StreamReader(const Stream &stream);
	};

} }

using namespace System::IO;